package mdt.utils;

import mdt.program.GraphManager;
import mdt.program.MDTGraphModel;
import mdt.ext.*;
import mdt.figure.*;
import mdt.model.*;
import org.tigris.gef.base.Editor;
import org.tigris.gef.base.LayerPerspective;
import org.tigris.gef.presentation.*;

import javax.swing.text.*;
import java.awt.*;

/**
 * Created by lambert on 2016/7/21.
 */
public class DemoGraphLoader {
	static Editor editor;
	static MDTGraphModel model;
	static LayerPerspective layer;

	enum FILLED {
		YES, NO
	}

	enum ITALIC {
		YES, NO
	}

	enum BOLD {
		YES, NO
	}

	enum DASHED {
		YES, NO
	}

	public synchronized static void loadDemoGraph(GraphManager.GraphInfo info) {
	try {

		editor = info.editor;
		if (editor.getFigs().size() > 0) return;

		model = (MDTGraphModel) info.graph.getGraphModel();
		layer = info.diagram.getLayer();

		IMDTComment richText = new MDTComment();
		model.addNode(richText);
		FigRichText frt = (FigRichText) layer.presentationFor(richText);
		StyledDocument document = prepareDocument(frt);
		appendDocument(document, "Error Handling", "Monospaced", 16, BOLD.YES, ITALIC.NO, Color.red, null);
		setBasicFigStyle(frt, 0, Color.black, FILLED.YES, Color.white, DASHED.NO, null);
		setBounds(frt, 632, 1352, 144, 26);

		FigRect rect = new FigRectExt(128, 1176, 672, 224);
		setBasicFigStyle(rect, 0, Color.black, FILLED.YES, new Color(221, 221, 221), DASHED.NO, null);
		addGroup(rect, frt);

		richText = new MDTComment();
		model.addNode(richText);
		frt = (FigRichText) layer.presentationFor(richText);
		document = prepareDocument(frt);
		appendDocument(document, "Basic Shapes", "Monospaced", 16, BOLD.YES, ITALIC.YES, Color.black, null);
		setBasicFigStyle(frt, 0, Color.black, FILLED.NO, Color.white, DASHED.NO, null);
		setBounds(frt, 568, 360, 141, 28);

		rect = new FigRectExt(111, 58, 640, 368);
		setBasicFigStyle(rect, 0, Color.black, FILLED.YES, new Color(219,219,219), DASHED.NO, null);
		addGroup(rect, frt);

		FigCircleExt circle = new FigCircleExt(convertCircleSVGToBounds(203, 122, 44 ,32));
		setBasicFigStyle(circle, 0, Color.black, FILLED.YES, new Color(102,153,255), DASHED.NO, null);
		editor.add(circle);

		rect = new FigRectExt(279, 90, 96, 64);
		setBasicFigStyle(rect, 1, new Color(255,51,51), FILLED.YES, Color.white, DASHED.YES, null);
		editor.add(rect);

		FigRRect rrect = new FigRRectExt(415, 90, 88, 56);
		setBasicFigStyle(rrect, 2, Color.black, FILLED.NO, Color.white, DASHED.NO, null);
		editor.add(rrect);

		FigLineExt line = new FigLineExt(new Point(183, 338), new Point(671, 338));
		setBasicFigStyle(line, 1, Color.black, FILLED.YES, Color.white, DASHED.NO, null);
		editor.add(line);

		FigPoly poly = new FigPolyExt();
		addPolyPoints(poly, "575,90 535,146 647,146 687,90 575,90");
		setBasicFigStyle(poly, 3, new Color(204,0,204), FILLED.YES, new Color(204,255,204), DASHED.NO, null);
		editor.add(poly);

		poly = new FigPolyExt();
		addPolyPoints(poly, "319,194 239,210 239,274 319,306 391,258 319,194");
		setBasicFigStyle(poly, 0, Color.black, FILLED.YES, Color.white, DASHED.NO, null);
		poly.setFillType(Fig.FILL_TYPE.LINEAR_GRADIENT);
		poly.setGradientEnd(new Color(153,255,153));
		editor.add(poly);

		FigSpline spline = new FigSplineExt();
		addPolyPoints(spline, "455,202 591,218 391,306");
		setBasicFigStyle(spline, 1, Color.black, FILLED.YES, Color.white, DASHED.NO, null);
		editor.add(spline);

		FigInk ink = new FigInkExt();
		addPolyPoints(ink, "583,202 579,203 576,208 572,218 571,222 569,227 569,231 "
				+ "567,240 567,268 570,272 575,273 610,273 615,271 630,261 634,254 " +
				"635,249 635,240 622,240 617,242 613,246 610,250 610,254 615,256 622,255 631,248 " +
				"635,246 639,249 643,250 647,249 651,246 655,245 654,249 654,253");
		setBasicFigStyle(ink, 1, Color.black, FILLED.NO, Color.white, DASHED.NO, null);
		editor.add(ink);

		richText = new MDTComment();
		model.addNode(richText);
		frt = (FigRichText) layer.presentationFor(richText);
		document = prepareDocument(frt);
		appendDocument(document, "• A pass criteria which requires ", "Monospaced", 12, BOLD.NO, ITALIC.NO, Color.black, null);
		appendDocument(document, "99.9%", "Monospaced", 14, BOLD.NO, ITALIC.NO, new Color(255,0,51), null);
		appendDocument(document, " of all transactions be processed within 115 ms\n• Average ", "Monospaced", 12, BOLD.NO, ITALIC.NO, Color.black, null);
		appendDocument(document, "latency under 10 ms", "MS Gothic", 12, BOLD.NO, ITALIC.YES, Color.black, null);
		appendDocument(document, "\n• ", "Monospaced", 12, BOLD.NO, ITALIC.NO, Color.black, null);
		appendDocument(document, "CPU utilization remains below 80% on all processing nodes", "Arial", 18, BOLD.NO, ITALIC.NO, Color.black, null);
		appendDocument(document, "\n• 0 ", "Monospaced", 12, BOLD.NO, ITALIC.NO, Color.black, null);
		appendDocument(document, "protocol", "Monospaced", 18, BOLD.NO, ITALIC.YES, Color.black, null);
		appendDocument(document, " errors reported ", "Monospaced", 12, BOLD.NO, ITALIC.NO, Color.black, null);
		appendDocument(document, "by the KPI", "Monospaced", 12, BOLD.NO, ITALIC.NO, Color.black, new Color(153, 255, 255));
		appendDocument(document, " dashboard of the product and the test driver ", "Monospaced", 12, BOLD.NO, ITALIC.NO, Color.black, null);
		setBounds(frt, 96, 448, 352, 152);
		frt.setFillType(Fig.FILL_TYPE.RADIAL_GRADIENT);
		frt.setGradientEnd(new Color(204,204,255));

		NetworkDevice ue = new NetworkDevice("UE");
		model.addNode(ue);
		FigNetworkDevice figUE = (FigNetworkDevice) layer.presentationFor(ue);
		figUE.setBounds(120, 656, 72, 800);
		setBasicFigStyle(figUE, 1, new Color(51,51,255), FILLED.NO, Color.white, DASHED.YES, null);

		NetworkDevice eNB = new NetworkDevice("eNB");
		model.addNode(eNB);
		FigNetworkDevice figeNB = (FigNetworkDevice) layer.presentationFor(eNB);
		figeNB.setBounds(232, 656, 80, 800);
		setBasicFigStyle(figeNB, 1, Color.black, FILLED.YES, Color.white, DASHED.NO, null);

		NetworkDevice MME = new NetworkDevice("MME");
		model.addNode(MME);
		FigNetworkDevice figMME = (FigNetworkDevice) layer.presentationFor(MME);
		document = prepareDocument(figMME);
		appendDocument(document, "MME", "Monospaced", 12, BOLD.YES, ITALIC.NO, Color.black, null);
		figMME.setBounds(344, 656, 80, 800);
		setBasicFigStyle(figMME, 1, Color.black, FILLED.YES, Color.white, DASHED.NO, null);
		figMME.setFillType(Fig.FILL_TYPE.LINEAR_REFLECT_GRADIENT);
		figMME.setGradientStart(new Color(255,102,102));


		NetworkDevice SGW = new NetworkDevice("SGW");
		model.addNode(SGW);
		FigNetworkDevice figSGW = (FigNetworkDevice) layer.presentationFor(SGW);
		document = prepareDocument(figSGW);
		appendDocument(document, "SGW", "Monospaced", 12, BOLD.YES, ITALIC.NO, new Color(255,51,102), null);
		figSGW.setBounds(464, 656, 80, 800);
		setBasicFigStyle(figSGW, 1, Color.black, FILLED.YES, Color.white, DASHED.NO, null);

		NetworkDevice PGW = new NetworkDevice("PGW");
		model.addNode(PGW);
		FigNetworkDevice figPGW = (FigNetworkDevice) layer.presentationFor(PGW);
		figPGW.setBounds(576, 656, 80, 800);
		setBasicFigStyle(figeNB, 1, Color.black, FILLED.YES, Color.white, DASHED.NO, null);

		NetworkDevice PCRF = new NetworkDevice("PCRF");
		model.addNode(PCRF);
		FigNetworkDevice figPCRF = (FigNetworkDevice) layer.presentationFor(PCRF);
		document = prepareDocument(figPCRF);
		appendDocument(document, "PCRF", "Monospaced", 12, BOLD.NO, ITALIC.NO, Color.black, null);
		figPCRF.setBounds(696, 656, 104, 800);
		setBasicFigStyle(figPCRF, 1, Color.black, FILLED.YES, new Color(153,255,153), DASHED.NO, null);

		addMessage(figUE, figeNB, ISendMessage.class, new Point(156,744), new Point(272, 744),
				"1. RCC Connection Request", new Rectangle(152, 715, 189, 19));

		addMessage(figeNB, figUE, IReplyMessage.class, new Point(272, 776), new Point(156, 776),
				"2. RRC Connection Setup", new Rectangle(156, 751, 178, 19));

		addMessage(figeNB, figMME, ISendMessage.class, new Point(272,816), new Point(384,816),
				"3. Attach Request", new Rectangle(279, 789, 131, 19));

		FigDiamond diamond = new FigDiamond(411, 856, 120, 76);
		DiamondChoice dc = new DiamondChoice();
		FigDiamondChoice figDC = new FigDiamondChoice(dc, diamond);
		setBasicFigStyle(figDC, 1, new Color(0,0,204), FILLED.YES, Color.white, DASHED.NO, null);
		document = prepareDocument(figDC);
		appendDocument(document, "Is GUTI known?", "Monospaced", 12, BOLD.NO, ITALIC.NO, Color.black, null);
		editor.add(figDC);

		addMessage(figMME, figDC, IReplyMessage.class, new Point(384,824),
				new Point(471,856), "Check GUTI", new Rectangle(410, 780, 70, 36), new Point(472,824));

		FigEdge linkSetupEdge = addMessage(figMME, figPCRF, IDualWayMessage.class, new Point(384,968), new Point(748,968),
				"Link Setup", new Rectangle(510, 946, 82, 19));
		setBasicFigStyle(linkSetupEdge, 1, Color.red, FILLED.YES, Color.red,
				DASHED.YES, null);

		FigNode srcAnchor, dstAnchor;
		dstAnchor = linkSetupEdge.createEdgeConnector(664, 968);
		editor.add(dstAnchor);
		addMessage(figDC, dstAnchor, ISendMessage.class, new Point(531,894), new Point(664,968),
				"Yes", new Rectangle(559, 871, 70, 20), new Point(664,896));

		FigEdge cancelLocationEdge = addMessage(figeNB, figPCRF, IDualWayMessage.class, new Point(272,1048), new Point(748,1048),
				"Cancel Location", new Rectangle(450, 1024, 121, 19));
		cancelLocationEdge.setDestArrowHead(new ArrowHeadGreater());
		cancelLocationEdge.setSourceArrowHead(new ArrowHeadDiamond());

		dstAnchor = cancelLocationEdge.createEdgeConnector(329,1048);
		editor.add(dstAnchor);
		addMessage(figDC, dstAnchor, IReplyMessage.class, new Point(411,894), new Point(329,1048),
				"Yes", new Rectangle(327, 874, 70, 20), new Point(328,896));


		FigShapedEdge tfe = addTextMessage(figUE, figPCRF, ITextEdge.class, new Rectangle(128, 1096, 652, 40));
		setBasicFigStyle(tfe, 1, Color.white, FILLED.YES, Color.yellow, DASHED.YES, null);
		document = prepareDocument(tfe);
		appendDocument(document, "Establishement of LTE IP-CAN Session", "Monospaced",
				20, BOLD.YES, ITALIC.NO, Color.black, null);

		FigEdge anotherAttEdge = addMessage(figeNB, figSGW, ISendMessage.class, new Point(272, 1216), new Point(504, 1216),
				"Another Attempt", new Rectangle(329, 1192, 119, 19));
		setBasicFigStyle(anotherAttEdge, 3, Color.blue, FILLED.YES, Color.blue, DASHED.YES, null);

		srcAnchor = new FigAnchorNode(new ConnectorAnchor(), 82,1161);
		editor.add(srcAnchor);
		dstAnchor = new FigAnchorNode(new ConnectorAnchor(), 848,1168);
		editor.add(dstAnchor);

		addMessage(srcAnchor, dstAnchor, IDualWayMessage.class, new Point(82,1161), new Point(848,1168),
				"A Line through the whole graph", new Rectangle(324, 1138, 241, 25));

		tfe = addTextMessage(figSGW, figPCRF, IArrowTextEdge.class, new Rectangle(520, 1264, 260, 76));
		setBasicFigStyle(tfe, 2, Color.white, FILLED.YES, Color.pink, DASHED.NO, null);
		document = prepareDocument(tfe);
		appendDocument(document, "RRC Configuration", "Monospaced", 14, BOLD.YES, ITALIC.YES, Color.yellow, null);
		FigArrowText fa = (FigArrowText)tfe.getShapeNode();
		fa.setArrowWidth(69);
		fa.setArrowHeight(76);
		fa.updateBounds();

		addMessage(figSGW, figeNB, IFailedMessage.class, new Point(504,1368), new Point(272,1368),
				"Interrupted", new Rectangle(353, 1343, 79, 29), new Point(353,1368));

	} catch (Exception e1) {
		System.err.println(e1);
	}
}

	public static FigEdge addMessage(FigNode srcNode, FigNode dstNode, Class edgeClass, Point startPoint, Point endPoint,
							  String text, Rectangle textBounds, Point ... interPoints) {
		Object srcPort = srcNode.deepHitPort(startPoint.x, startPoint.y);
		Object dstPort = dstNode.deepHitPort(endPoint.x, endPoint.y);
		Object conn = model.connect(srcPort, dstPort, edgeClass);
		FigEdgePolyEditable edge = (FigEdgePolyEditable)layer.presentationFor(conn);
		FigPoly poly = new FigPoly();
		poly.addPoint(startPoint);
		addPolyPoints(poly, interPoints);
		poly.addPoint(endPoint);
		poly.setFilled(false);
		edge.setFig(poly);
		setBasicFigStyle(edge, 1, Color.black, FILLED.YES, Color.black,
				edgeClass.equals(IReplyMessage.class) ? DASHED.YES : DASHED.NO, null);

		StyledDocument document = prepareDocument(edge);
		appendDocument(document, text, "Monospaced", 12, BOLD.NO, ITALIC.NO, Color.black, null);
		FigTextMDT figText = edge.getFigText();
		setBasicFigStyle(figText, 0, Color.black, FILLED.NO, Color.white, DASHED.NO, null);
		figText.setEditable(true);
		PathItemPlacement itemPlace = (PathItemPlacement)edge.getPathItemPlacementStrategy(figText);
		itemPlace.setAnchorOffset(0);
		itemPlace.setAnchorPercent(50);
		figText.setBounds(textBounds);
		return edge;
	}

	public static FigShapedEdge addTextMessage(FigNode srcNode, FigNode dstNode, Class edgeClass, Rectangle bounds) {
		Object srcPort = srcNode.getOwner();
		Object dstPort = dstNode.getOwner();
		Object conn = model.connect(srcPort, dstPort, edgeClass);
		FigShapedEdge edge = (FigShapedEdge)layer.presentationFor(conn);
		setBasicFigStyle(edge, 1, Color.black, FILLED.YES, Color.white, DASHED.NO, null);
		edge.setBounds(bounds);
		return edge;
	}

	public static void addPolyPoints(FigPoly poly, Point ... points) {
		for (Point p : points) {
			poly.addPoint(p);
		}
	}

	public static void addPolyPoints(FigPoly poly, String str) {
		String[] strPs = str.split(" ");
		for (String strP : strPs) {
			int px = Integer.parseInt(strP.substring(0, strP.indexOf(',')));
			int py = Integer.parseInt(strP.substring(strP.indexOf(',') + 1));
			poly.addPoint(px, py);
		}
	}

	public static Rectangle convertCircleSVGToBounds(int cx, int cy, int rx, int ry) {
		return new Rectangle(cx - rx,
				cy - ry,
				rx * 2,
				ry * 2);
	}

	public static StyledDocument prepareDocument(FigShapedEdge fig) {
		FigNodeEditable figNode = (FigNodeEditable)fig.getFig();
		StyledDocument doc = figNode.getFigText().getDocument();
		try {
			doc.remove(0, doc.getLength());
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
		return doc;
	}

	public static StyledDocument prepareDocument(FigNodeEditable fig) {
		StyledDocument document = (StyledDocument)fig.getFigText().getDocument();
		try {
			document.remove(0, document.getLength());
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
		return document;
	}

	public static StyledDocument prepareDocument(FigEdgePolyEditable fig) {
		StyledDocument document = (StyledDocument)fig.getFigText().getDocument();
		try {
			document.remove(0, document.getLength());
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
		return document;
	}

	public static void appendDocument(StyledDocument doc, String text,
							   String fontFamily, int fontSize, BOLD bold, ITALIC italic,
							   Color foreground, Color background) {
		MutableAttributeSet as = new SimpleAttributeSet();
		StyleConstants.setFontSize(as, fontSize);
		StyleConstants.setBold(as, bold == BOLD.YES);
		StyleConstants.setItalic(as, italic == ITALIC.YES);
		StyleConstants.setFontFamily(as, fontFamily);
		StyleConstants.setForeground(as, foreground);
		if (background != null)
			StyleConstants.setBackground(as, background);
		try {
			doc.insertString(doc.getLength(), text, as);
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
	}

	public static void setBasicFigStyle(Fig fig, int lineWidth, Color lineColor,
								 FILLED filled, Color fillColor, DASHED dashed, String dashStr) {
		fig.setLineWidth(lineWidth);
		fig.setLineColor(lineColor);
		fig.setFilled(filled == FILLED.YES);
		fig.setFillColor(fillColor);
		fig.setDashed(dashed == DASHED.YES);
		if (dashStr != null) {
			fig.setDashedString(dashStr);
		}
	}

	public static void setBounds(Fig fig, int x, int y, int width, int height) {
		fig.setBounds(x, y, width, height);
		fig.damage();
	}

	public static void addGroup(Fig ... figs) {
		FigGroup group = new FigGroup();
		group.setIntegrited(false);
		for (Fig fig : figs) {
			editor.remove(fig);
			group.addFig(fig);
		}
		editor.add(group);
	}
}
